# ==================4.字典==================
# @.可变类型与不可变类型

"""
1. 序列是以连续的整数为索引，与此不同的是，字典以"关键字"为索引，关键字可以是任意不可变类型，通常用字符串
或数值。
2. 字典是 Python 唯一的一个 映射类型，字符串、元组、列表属于序列类型。
那么如何快速判断一个数据类型 X 是不是可变类型的呢？两种方法：
1. 麻烦方法：用 id(X) 函数，对 X 进行某种操作，比较操作前后的 id ，如果不一样，则 X 不可变，如果一样，则
X 可变。
2. 便捷方法：用 hash(X) ，只要不报错，证明 X 可被哈希，即不可变，反过来不可被哈希，即可变。


1. 整数 i 在加 1 之后的 id 和之前不一样，因此加完之后的这个 i (虽然名字没变)，但不是加之前的那个 i 了，因
此整数是不可变类型。
2. 列表 l 在附加 'Python' 之后的 id 和之前一样，因此列表是可变类型。
"""
i = 1
print(id(1))
i = i + 2
print(id(i))

s = [1, 2]
print(id(s))
s.append(12)
print(id(s))
"""
1. 数值、字符和元组 都能被哈希，因此它们是不可变类型。
2. 列表、集合、字典不能被哈希，因此它是可变类型。
"""
print('数值', hash(1212))
print('字符', hash('name'))
print('元组', hash('name'))
print('列表', hash('name'))
print('集合', hash('name'))
print('字典', hash('name'))

# @.字典的定义
"""
字典 是无序的 键:值（ key:value ）对集合，键必须是互不相同的（在同一个字典之内）。
1. dict 内部存放的顺序和 key 放入的顺序是没有关系的。
2. dict 查找和插入的速度极快，不会随着 key 的增加而增加，但是需要占用大量的内存。
字典 定义语法为 {元素1, 元素2, ..., 元素n}
1. 其中每一个元素是一个「键值对」-- 键:值 ( key:value )
2. 关键点是「大括号 {}」,「逗号 ,」和「冒号 :」
3. 大括号 -- 把所有元素绑在一起
4. 逗号 -- 将每个键值对分开
5. 冒号 -- 将键和值分开


"""
dic1 = {1: 'one', 2: 'two', 3: 'three'}

print(type(dic1))
# @.创建和访问字典
"""
通过字符串或数值作为 key 来创建字典。
注意：如果我们取的键在字典中不存在，会直接报错 KeyError 。
"""
dic1 = {1: 'one', '1': 12, 2: 'two', 3: 'three', }
print(dic1[1])  # one
print(dic1['1'])  # 12

# 通过构造函数 dict 来创建字典。
# 通过 key 直接把数据放入字典中，但一个 key 只能对应一个 value ，多次对一个 key 放入 value ，后面的值
# 会把前面的值冲掉。

dict_1 = dict()

print(dict_1)  # {}

dict_1['a'] = '123'
dict_1['b'] = '456'
print(dict_1)  # {'a': '123', 'b': '456'}

# dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs


dict_2 = dict([('a', 12), ('b', 2), ('c', 3)])

print(dict_2)  # {'a': 12, 'b': 2, 'c': 3}

#  dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example:
dict_3 = dict(one=1, two=2)
print(dict_3)  # {'one': 1, 'two': 2}

# @.字典的内置方法
"""
dict.fromkeys(seq[, value])
dict.keys()
"""

# 1. dict.fromkeys(seq[, value]) 用于创建一个新字典，以序列 seq 中元素做字典的键， value 为字典所有键对 应的初始值。
seq = ('name', 'age', 'sex',)
dict_4 = dict.fromkeys(seq)

print(dict_4)
# {'name': None, 'age': None, 'sex': None}

dict_5 = dict.fromkeys(seq, 12)
print(dict_5)  # {'name': 12, 'age': 12, 'sex': 12}
print('新的数据字典为:|%s|' % str(dict_5))

# 2. dict.keys() 返回一个可迭代对象，可以使用 list() 来转换为列表，列表为字典中的所有键。
dict5_keys = dict_5.keys()

print('dict5_keys', dict5_keys)  # dict_keys(['name', 'age', 'sex'])

dict5_keysList = list(dict5_keys)
print('dict5_keysList', dict5_keysList)  # ['name', 'age', 'sex']

# 3. dict.values() 返回一个迭代器，可以使用 list() 来转换为列表，列表为字典中的所有值

dict5_values = dict_5.values()
print(dict5_values)  # dict_values([12, 12, 12])
dict5_values_list = list(dict5_values)
print(dict5_values_list)  # [12, 12, 12]

# 4. dict.items() 以列表返回可遍历的 (键, 值) 元组数组。
print(dict_5.items())  # dict_items([('name', 12), ('age', 12), ('sex', 12)])
print(list(dict_5.items()))  # [('name', 12), ('age', 12), ('sex', 12)]

# 5. dict.get(key, default=None) 返回指定键的值，如果值不在字典中返回默认值。
print(dict_5.get('name'))  # 12
print(dict_5.get('email'))  # None

# 6. dict.setdefault(key, default=None) 和 get() 方法 类似, 如果键不存在于字典中，将会添加键并将值设为默认值。
dict_6 = {'name': 12, 'age': 12, 'sex': 12}
dict_6.setdefault('phone')
print(dict_6.setdefault('email', 'xxx@qq.com'))  # xxx@qq.com
print(dict_6)  # {'name': 12, 'age': 12, 'sex': 12, 'email': 'xxx@qq.com'}

# 7. key in dict in 操作符用于判断键是否存在于字典中，如果键在字典 dict 里返回 true ，否则返回 false 。
# 而 not in 操作符刚好相反，如果键在字典 dict 里返回 false ，否则返回 true 。

print('name' in dict_6)  # True
print('email' in dict_6)  # True
print('phone' in dict_6)  # True
print('wechat' in dict_6)  # False

# 8. dict.pop(key[,default]) 删除字典给定键 key 所对应的值，返回值为被删除的值。
# key 值必须给出。若 key不存在，则返回 default 值。
dict_8 = {'name': '静静', 'age': 12, 'sex': '女'}

print(dict_8.pop('name'))  # 静静
print(dict_8)  # {'age': 12, 'sex': '女'}

# 9. del dict[key] 删除字典给定键 key 所对应的值。
del dict_8['age']
print(dict_8)  # {'sex': '女'}

# 10. dict.popitem() 随机返回并删除字典中的一对键和值，如果字典已经为空，却调用了此方法，就报出KeyError异常。
dict_10 = {'name': '静静', 'age': 12, 'sex': '女'}

dict_10.popitem()
print(dict_10)  # {'name': '静静', 'age': 12}
dict_10.popitem()
print(dict_10)  # {'name': '静静'}
dict_10.popitem()
print(dict_10)  # {}
# dict_10.popitem()  # KeyError: 'popitem(): dictionary is empty'

# 11. dict.clear() 用于删除字典内所有元素。
dict_11 = {'name': '静静', 'age': 12, 'sex': '女'}
print(dict_11)
dict_11.clear()
print(dict_11)

# 12. dict.copy() 返回一个字典的浅复制。
print(dict_11.copy())

dic1 = {'user': 'username', 'num': [1, 2, 3]}
# 引用对象
dic2 = dic1
# 深拷贝父对象（一级目录），子对象（二级目录）不拷贝，还是引用
dic3 = dic1.copy()
print(id(dic1))  # 148635574728
print(id(dic2))  # 148635574728
print(id(dic3))  # 148635574344
# 修改 data 数据
dic1['user'] = 'root'
dic1['num'].remove(1)
# 输出结果
print(dic1)  # {'user': 'root', 'num': [2, 3]}
print(dic2)  # {'user': 'root', 'num': [2, 3]}
print(dic3)  # {'user': 'runoob', 'num': [2, 3]}

# 13. dict.update(dict2) 把字典参数 dict2 的 key:value 对 更新到字典 dict 里
dict_13 = {
    'name': '张三',
    'age': 18,
    'sex': '女'
}
dict_13_up = {'name': '涵涵', 'age': 30, }
dict_13.update(dict_13_up)

print('dict_13_up', dict_13_up)
print('dict_13', dict_13)

"""
练习
dic = {
 'python': 95,
 'java': 99,
 'c': 100
}




"""
print('===========练习=========')
dict_test = {
    'python': 95,
    'java': 99,
    'c': 100
}
index = 0
# 1. 字典的长度是多少
index += 1
print(index, len(dict_test))
# 2. 请修改'java' 这个key对应的value值为98
dict_test['java'] = 98
index += 1
print(index, dict_test)
# 3. 删除 c 这个key
dict_test.pop('c')
index += 1
print(index, dict_test)
# 4. 增加一个key-value对，key值为 php, value是90
dict_test.setdefault('php', 90)
index += 1
print(index, dict_test)

# 5. 存储在列表里获取所有的key值，
index += 1
print(index, list(dict_test.keys()))

# 6. 获取所有的value值，存储在列表里
index += 1
print(index, list(dict_test.values()))

# 7. 判断 javascript 是否在字典中
index += 1
print(index, 'javascript' in dict_test)

# 8. 获得字典里所有value 的和
index += 1
print(index, sum(dict_test.values()))

# 9. 获取字典里最大的value
index += 1
print(index, max(dict_test.values()))

# 10. 获取字典里最小的value
index += 1
print(index, min(dict_test.values()))

# 11. 字典 dic1 = {'php': 97}， 将dic1的数据更新到dic中
dic1 = {'php': 97}
dict_test.update(dic1)
index += 1
print(index, dict_test)
